<?
/**
 * 	The time-line class.
 *
 *	@copyright	2010 - oneDot only<br>
 *  You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.<br>
 *  The content is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.  see the GNU General Public License for more details.
 *
 *	@author		Koen Betsens <we@onedotonly.be>
 *  @package	Global
 */

/**
 * The time-line class.
 *
 * All "calendar" (or time related) calls are happening trough the CAL object. The CAL session is focused on current or future displays, take this in account ( ">= now()" ).
 * The main concept of the CALENDAR class is the fast and flexible approach of many-to-many time-line references.  
 *
 * <code>
 * global $CAL = new CALENDAR( date_format, time_format )
 * </code>
 *
 * @package		Global
 *
 * @return		Object	CALENDAR class
 */
class CALENDAR {
	
	/**
	 * Prefered display of "date"
	 *
	 * @name date_format	default "%d.%m %Y" 
	 */
	const date_format	= "%d.%m %Y";
	
	/**
	 * Prefered display of "time"
	 *
	 * @name date_format	default "%H.%i" 
	 */
	const time_format	= "%H.%i";
	
	/**
	 * The weekday local shortcodes
	 *
	 * @var			array
	 * @deprecated	this isn't the correct solution, should be part of the translate() functionality
	 * @todo		rework to translate() > explode string
	 */
	public $days = array(
		"nl" => array( "zo","ma","di","wo","do","vr","za" ),
		"fr" => array( "zo","ma","di","wo","do","vr","za" ),
		"en" => array( "zo","ma","di","wo","do","vr","za" )
	);
	
	/**
	 * Constructs the Calendar object
	 *
	 * @param 	string 	$date_format	optional prefered display of "date", defaults to %d.%m %Y
	 * @param 	string 	$time_format	optional prefered display of "time", defaults to %H.%i
	 * @return	object
	 */
	function __construct( $date_format = self::date_format, $time_format = self::time_format ) {
		
		$this->dformat = $date_format;
		$this->tformat = $time_format;

	}

	/**
	 * Request single calendar row
	 *
	 * @param 	string 	$date		the date notation for nearest by search (abs) or now()
	 * @param 	string 	$type		the calendar type string
	 * @param 	string 	$objtype	the object type string
	 * @return	array	single row or empty array
	 */
	public function get( $date, $type = "cal.single", $objtype = false ) {
		global $DB;
		
		$condt = ( $objtype )? "otype=" . $DB->type( $objtype ) . " &&" : "";
		
		
		if( $date != "now()" )
			$date  = $DB->smartq( $date );
		
		return $DB->get( $type, "$condt active order by abs( datediff( date, $date )), rank desc, rand()" );

	}
	
#	Retreive single calendar row.
	public function get_node( $date, $type = "cal.single", $objtype = false, $objid = false ) {
		global $DB;
		
		$condt = ( $objtype )? "otype=<%type:$objtype%> &&" : "";
		$condt.= ( $objid )  ? "objid=$objid &&" : "";
		
		if( $date != "now()" ) $date  = $DB->smartq( $date );
		$id = $DB->get_key( $type, "$condt active order by abs( datediff( date, $date )), rank desc, rand()" );

		return new CALNODE( $type, (int) $id, 0, array( "datestr"=> $this->dformat, "timestr"=> $this->tformat ));

	}
	
	
#	Retreive multiple calendar rows with given key(s).
	public function filter_key( $date, $diff, $columns = "ID", $type = "cal.single", $objtype = false, $loc = false, $limit = 24 ) {
		global $DB;
		
						$condt[] = $this->condt_diff( $date, $diff );
		if( $objtype )	$condt[] = $this->condt_objtype( $objtype );
		if( $loc )		$condt[] = $this->condt_location( $loc );
		
		return $DB->filter_key( $type, implode( " && ", $condt ) . " && active = 1 order by date, rank desc, rand() limit $limit", $columns );
	}
	
#	Retreive multiple calendar rows with given key(s), based on condition(s).
	public function filter_key_condt( $date, $diff = 31, $condt_str = "objid order by date desc", $columns = "ID", $type = "cal.single", $objtype = false, $loc = false ) {
		global $DB;
		
						$condt[] = $this->condt_diff( $date, $diff );
		if( $objtype )	$condt[] = $this->condt_objtype( $objtype );
		if( $loc )		$condt[] = $this->condt_location( $loc );
		if( is_int( $condt_str )) $condt_str = "objid = $condt_str";
		
		return $DB->filter_key( $type, implode( " && ", $condt ) . " && active && $condt_str", $columns );
	}
	
#	Retreive multiple calendar rows with given key(s) by objects
	public function filter_key_by_object( $type, $objtype, $condt, $columns = "ID", $raw = false, $limit = 24 ) {
		global $DB;
		
		if( is_int( $condt )) $condt = "objid = $condt" . ( $raw? "&& $raw" : " && active && date >= now() limit $limit" );
		if( is_array( $columns )) $columns = implode( ",", $columns );
		
		return $DB->filter_key( $type, "otype = <%type:$objtype%> && $condt", $columns ); 
		
	}
	
#	Retreive multiple calendar rows, extended keys.
	public function filter( $date, $diff, $type = "cal.single", $objtype = false, $loc = false, $limit = 24 ) {
		
		$columns = "*, date_format( date, '$this->dformat') as dstring, date_format( date, '$this->tformat') as tstring, if( nameid, <%lang:nameid%>, (select <%lang:obj.nameid%> from mod_object as obj where obj.ID = objid)) as name";
		
		return $this->filter_key( $date, $diff, $columns, $type, $objtype, $loc, $limit );
	}
	
	
#	Retreive multiple calnode objects.
	public function filter_nodes( $date, $diff, $type = "cal.single", $objtype = false, $loc = false, $limit = 24 ) {
		
		$nodes = array();
		
		if( $results = $this->filter_key( $date, $diff, "ID", $type, $objtype, $loc, $limit ))  		
			foreach( $results as $row ) $nodes[] = new CALNODE( $type, (int) $row[ 'ID' ], 0, array( "datestr"=> $this->dformat, "timestr"=> $this->tformat ));
				
		return $nodes;
	}
	
	#	Retreive multiple calnode objects.
	public function filter_nodes_by_condt( $type, $condt = "active" ) {
		global $DB;
		
		$nodes = array();
		
		if( $results = $DB->filter_key( $type, $condt ))  		
			foreach( $results as $row ) $nodes[] = new CALNODE( $type, (int) $row[ 'ID' ], 0, array( "datestr"=> $this->dformat, "timestr"=> $this->tformat ));
		
		return $nodes;
	}

	
	
#	Retreive multiple calnode objects by object.
	public function filter_nodes_by_object( $type, $objtype, $condt, $raw = false ) {
		
		if( is_int( $condt )) $condt = "objid = $condt" . ( $raw? "&& $raw" : " && active && date >= now() limit 24 " );
		
		return $this->filter_nodes_by_condt( $type, "otype = <%type:$objtype%> && $condt" );
	}


/// INTERNAL FUNCTIONS (non DB)

#	Internal render diff string
	private function condt_diff( $date, $diff ) {
		global $DB;
		
		if( $date != "now()" )
			$date  = $DB->smartq(( $date )? $date : $this->smartday( "now" ));
		
		return ( $diff )?
			"date >= $date && " . ( is_int( $diff )? "datediff( date, $date ) ". (( $diff > 0 )? "<": ">" ) ." $diff ": "date <= ". $DB->smartq( $diff )) : "date = $date";
	} 

#	Internal render object types string
	private function condt_objtype( $value ) {
		global $DB;
		
		if( is_array( $value ))

			 foreach( $value as $objstr ) $otype[] = $DB->type( $objstr );
		else $otype = (int) $DB->type( $value );
		
		return "objid && otype " . ( is_int( $otype )? "= $otype" : "in( ". implode( ",", $otype ) ." )" );
	}
	
#	Internal render locations string
	private function condt_location( $value ) {
		global $DB;
		
		if( is_array( $value ))
			foreach ( $value as $locid ) $loc[] = $locid;
		
		return "location " . (( $loc )? "in( ". implode( ",", $loc ) ." )" : "= $value" );
	}
	
#	Internal reposition of start/end day, between 06:00 local & 06:00 next day
#	(better way welcome)
	public function smartday( $date, $end_of_day = false ) {
		
		$time = strtotime( $date . ( $end_of_day? "+ 1 days" : "" ));
		return date( "Y-m-d 06:00:00", $time );
	}

			
}

?>